"""
指数成分数据模块
查询市场上的指数成分信息数据
"""
import time
from typing import Dict, List, Optional
from datetime import datetime, timedelta
from loguru import logger

try:
    import okx.MarketData as MarketData
except ImportError:
    logger.warning("okx SDK未安装，请运行: pip install okx")
    MarketData = None


class IndexComponentsManager:
    """指数成分数据管理器"""
    
    # 限速配置：20次/2s
    RATE_LIMIT_REQUESTS = 20
    RATE_LIMIT_WINDOW = 2.0  # 秒
    
    def __init__(self, sandbox: bool = True):
        """
        初始化指数成分数据管理器
        
        Args:
            sandbox: 是否使用模拟盘，True=模拟盘(1)，False=实盘(0)
        """
        if MarketData is None:
            raise ImportError("okx SDK未安装，请运行: pip install okx")
        
        self.sandbox = sandbox
        flag = "1" if sandbox else "0"
        
        # 初始化OKX行情数据API
        self.market_api = MarketData.MarketAPI(flag=flag)
        
        # 限速控制
        self.request_times: List[float] = []  # 请求时间戳列表
        
        # 数据缓存
        self.components_cache: Dict[str, Dict] = {}  # index -> components_data
        self.cache_expire_time: Dict[str, datetime] = {}  # index -> expire_time
        self.cache_duration = timedelta(minutes=10)  # 缓存10分钟
        
        logger.info(f"指数成分数据管理器已初始化 (模式: {'模拟盘' if sandbox else '实盘'})")
    
    def _check_rate_limit(self):
        """
        检查并执行限速
        限速规则：20次/2s (IP)
        """
        now = time.time()
        
        # 移除2秒前的请求记录
        self.request_times = [t for t in self.request_times 
                             if now - t < self.RATE_LIMIT_WINDOW]
        
        # 如果达到限速上限，等待
        if len(self.request_times) >= self.RATE_LIMIT_REQUESTS:
            oldest_request = self.request_times[0]
            wait_time = self.RATE_LIMIT_WINDOW - (now - oldest_request)
            
            if wait_time > 0:
                logger.debug(f"触发限速，等待 {wait_time:.2f} 秒")
                time.sleep(wait_time)
                # 重新计算
                now = time.time()
                self.request_times = [t for t in self.request_times 
                                     if now - t < self.RATE_LIMIT_WINDOW]
        
        # 记录本次请求
        self.request_times.append(now)
    
    def get_index_components(self, index: str, use_cache: bool = True) -> Dict:
        """
        获取指数成分数据
        
        Args:
            index: 指数，如 BTC-USD
            use_cache: 是否使用缓存
            
        Returns:
            指数成分数据字典，包含：
            - components: 成分列表
            - last: 最新指数
            - ts: 数据返回时间（毫秒时间戳）
        """
        # 检查缓存
        if use_cache and index in self.components_cache:
            expire_time = self.cache_expire_time.get(index)
            if expire_time and datetime.now() < expire_time:
                logger.debug(f"从缓存获取指数成分数据: {index}")
                return self.components_cache[index]
        
        # 执行限速检查
        self._check_rate_limit()
        
        try:
            logger.info(f"获取指数成分数据: {index}")
            result = self.market_api.get_index_components(index=index)
            
            # 检查响应
            if result.get("code") != "0":
                error_msg = result.get("msg", "未知错误")
                logger.error(f"获取指数成分数据失败: {error_msg}")
                raise RuntimeError(f"API错误: {error_msg}")
            
            # 提取数据
            data = result.get("data", [])
            if not data:
                logger.warning(f"未获取到指数成分数据: {index}")
                return {}
            
            # 通常返回一个对象
            components_data = data[0] if isinstance(data, list) else data
            
            logger.info(f"获取指数成分数据成功: {index}")
            
            # 更新缓存
            if use_cache:
                self.components_cache[index] = components_data
                self.cache_expire_time[index] = datetime.now() + self.cache_duration
            
            return components_data
            
        except Exception as e:
            logger.error(f"获取指数成分数据异常: {e}")
            raise
    
    def get_components_list(self, index: str, use_cache: bool = True) -> List[Dict]:
        """
        获取指数成分列表
        
        Args:
            index: 指数
            use_cache: 是否使用缓存
            
        Returns:
            成分列表，每个成分包含：
            - exch: 交易所
            - symbol: 交易对
            其他可能的字段
        """
        data = self.get_index_components(index, use_cache)
        
        if data and "components" in data:
            components = data["components"]
            if isinstance(components, list):
                return components
        
        return []
    
    def get_index_value(self, index: str, use_cache: bool = True) -> Optional[float]:
        """
        获取指数最新值
        
        Args:
            index: 指数
            use_cache: 是否使用缓存
            
        Returns:
            指数最新值
        """
        data = self.get_index_components(index, use_cache)
        
        if data and "last" in data:
            return float(data["last"])
        
        return None
    
    def get_components_details(self, index: str, use_cache: bool = True) -> Dict:
        """
        获取指数成分详细信息
        
        Args:
            index: 指数
            use_cache: 是否使用缓存
            
        Returns:
            详细信息字典
        """
        data = self.get_index_components(index, use_cache)
        
        if not data:
            return {}
        
        components = self.get_components_list(index, use_cache)
        index_value = self.get_index_value(index, use_cache)
        
        # 统计交易所分布
        exchange_count = {}
        for comp in components:
            exch = comp.get("exch", "unknown")
            exchange_count[exch] = exchange_count.get(exch, 0) + 1
        
        # 格式化时间戳
        ts = int(data.get("ts", 0))
        timestamp_str = datetime.fromtimestamp(ts / 1000).strftime("%Y-%m-%d %H:%M:%S") if ts > 0 else ""
        
        return {
            "index": index,
            "index_value": index_value,
            "component_count": len(components),
            "exchanges": list(exchange_count.keys()),
            "exchange_distribution": exchange_count,
            "timestamp": timestamp_str,
            "timestamp_ms": ts,
            "components": components,
        }
    
    def compare_multiple_indexes(self, indexes: List[str]) -> Dict[str, Dict]:
        """
        比较多个指数的成分信息
        
        Args:
            indexes: 指数列表
            
        Returns:
            字典，key为指数，value为成分详细信息
        """
        results = {}
        
        for index in indexes:
            try:
                details = self.get_components_details(index)
                results[index] = details
            except Exception as e:
                logger.error(f"获取 {index} 指数成分数据失败: {e}")
                results[index] = None
        
        return results
    
    def get_component_exchanges(self, index: str, use_cache: bool = True) -> List[str]:
        """
        获取指数成分涉及的交易所列表
        
        Args:
            index: 指数
            use_cache: 是否使用缓存
            
        Returns:
            交易所列表
        """
        components = self.get_components_list(index, use_cache)
        
        exchanges = set()
        for comp in components:
            exch = comp.get("exch")
            if exch:
                exchanges.add(exch)
        
        return sorted(list(exchanges))
    
    def get_components_by_exchange(self, index: str, exchange: str,
                                   use_cache: bool = True) -> List[Dict]:
        """
        获取指定交易所的指数成分
        
        Args:
            index: 指数
            exchange: 交易所名称
            use_cache: 是否使用缓存
            
        Returns:
            该交易所的成分列表
        """
        components = self.get_components_list(index, use_cache)
        
        return [comp for comp in components if comp.get("exch") == exchange]
    
    def clear_cache(self, index: Optional[str] = None):
        """
        清除缓存
        
        Args:
            index: 指数，如果为None则清除所有缓存
        """
        if index:
            if index in self.components_cache:
                del self.components_cache[index]
            if index in self.cache_expire_time:
                del self.cache_expire_time[index]
            logger.info(f"已清除 {index} 的缓存")
        else:
            self.components_cache.clear()
            self.cache_expire_time.clear()
            logger.info("已清除所有指数成分缓存")
    
    def get_cache_stats(self) -> Dict:
        """
        获取缓存统计信息
        
        Returns:
            缓存统计字典
        """
        total_cached = len(self.components_cache)
        valid_cached = sum(1 for key in self.components_cache.keys()
                          if key in self.cache_expire_time and
                          datetime.now() < self.cache_expire_time[key])
        
        return {
            "total_cached": total_cached,
            "valid_cached": valid_cached,
            "expired_cached": total_cached - valid_cached,
            "cache_duration_seconds": self.cache_duration.total_seconds(),
        }


# 便捷函数
def get_index_components(index: str, sandbox: bool = True) -> Dict:
    """
    便捷函数：获取指数成分数据
    
    Args:
        index: 指数
        sandbox: 是否使用模拟盘
        
    Returns:
        指数成分数据字典
    """
    manager = IndexComponentsManager(sandbox=sandbox)
    return manager.get_index_components(index)


def get_components_list(index: str, sandbox: bool = True) -> List[Dict]:
    """
    便捷函数：获取指数成分列表
    
    Args:
        index: 指数
        sandbox: 是否使用模拟盘
        
    Returns:
        成分列表
    """
    manager = IndexComponentsManager(sandbox=sandbox)
    return manager.get_components_list(index)


def get_components_details(index: str, sandbox: bool = True) -> Dict:
    """
    便捷函数：获取指数成分详细信息
    
    Args:
        index: 指数
        sandbox: 是否使用模拟盘
        
    Returns:
        详细信息字典
    """
    manager = IndexComponentsManager(sandbox=sandbox)
    return manager.get_components_details(index)
